home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / pc / ABUSESRC.ZIP / AbuseSrc / abuse / src / cache.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-04-15  |  29.5 KB  |  1,293 lines

  1. #include "cache.hpp"
  2. #include "lisp.hpp"
  3. #include "video.hpp"
  4. #include "dprint.hpp"
  5. #include "exitproc.hpp"
  6. #include "lcache.hpp"
  7. #include "status.hpp"
  8. #include "game.hpp"
  9. #include "lisp_gc.hpp"
  10. #include "level.hpp"
  11. #include "status.hpp"
  12. #include "crc.hpp"
  13. #include "specache.hpp"
  14.  
  15. #ifndef __POWERPC__
  16. #include <sys/stat.h>
  17. #endif
  18.  
  19. #include <fcntl.h>
  20. char lfname[100]="";          // name of compiled lisp code cache file
  21.  
  22. #define touch(x) { (x)->last_access=last_access++; \
  23.            if ((x)->last_access<0) { normalize(); (x)->last_access=1; } }
  24.  
  25. extern char *symbol_str(char *name);
  26.  
  27. crc_manager crc_man;
  28.  
  29. int past_startup=0;
  30.  
  31. int crc_man_write_crc_file(char *filename)
  32. {
  33.   return crc_man.write_crc_file(filename);
  34. }
  35.  
  36. int crc_manager::write_crc_file(char *filename)  // return 0 on failure
  37. {
  38.   char msg[100];
  39.   sprintf(msg,symbol_str("calc_crc"));  // this may take some time, show the user a status indicator
  40.   if (stat_man) stat_man->push(msg,NULL);
  41.  
  42.   int i,total=0;
  43.   for (i=0;i<total_files;i++)
  44.   {
  45.     int failed=0;
  46.     get_crc(i,failed);
  47.  
  48.     if (failed)
  49.     {
  50.       jFILE *fp=new jFILE(get_filename(i),"rb");
  51.       if (!fp->open_failure())
  52.       {
  53.     set_crc(i,crc_file(fp));
  54.     total++;
  55.       }
  56.       delete fp;
  57.     } else total++;
  58.     if (stat_man)
  59.       stat_man->update(i*100/total_files);
  60.   }
  61.   if (stat_man) stat_man->pop();
  62.   jFILE *fp=new jFILE("#net_crc","wb");
  63.   if (fp->open_failure())
  64.   {
  65.     delete fp;
  66.     return 0; 
  67.   }
  68.  
  69.   fp->write_short(total);
  70.   total=0;
  71.   for (i=0;i<total_files;i++)
  72.   {
  73.     ulong crc;
  74.     int failed=0;
  75.     crc=get_crc(i,failed);
  76.     if (!failed)
  77.     {
  78.       fp->write_long(crc);
  79.       uchar len=strlen(get_filename(i))+1;
  80.       fp->write_byte(len);
  81.       fp->write(get_filename(i),len);
  82.       total++;
  83.     }
  84.   }
  85.   delete fp;
  86.   return 1;  
  87. }
  88.  
  89. int crc_manager::load_crc_file(char *filename)
  90. {
  91.   bFILE *fp=open_file(filename,"rb");
  92.   if (fp->open_failure())
  93.   {
  94.     delete fp;
  95.     return 0;
  96.   } else
  97.   {
  98.     short total=fp->read_short();
  99.     int i;
  100.     for (i=0;i<total;i++)
  101.     {
  102.       char name[256];
  103.       ulong crc=fp->read_long();
  104.       uchar len=fp->read_byte();
  105.       fp->read(name,len);
  106.       set_crc(get_filenumber(name),crc);
  107.     }
  108.     delete fp;
  109.   }
  110.   return 1;  
  111. }
  112.  
  113. void crc_manager::clean_up()
  114. {
  115.   for (int i=0;i<total_files;i++)
  116.     delete files[i];
  117.   if (total_files)
  118.     jfree(files);
  119.   total_files=0;
  120.   files=NULL;
  121. }
  122.  
  123. crced_file::~crced_file()
  124. {
  125.   jfree(filename);
  126. }
  127.  
  128. crced_file::crced_file(char *name) 
  129.   filename=strcpy((char *)jmalloc(strlen(name)+1,"crc_file"),name);
  130.   crc_calculated=0;
  131. }
  132.  
  133. crc_manager::crc_manager()
  134. {
  135.   total_files=0;
  136.   files=NULL;
  137. }
  138.  
  139. int crc_manager::get_filenumber(char *filename)
  140. {
  141.   for (int i=0;i<total_files;i++)
  142.     if (!strcmp(filename,files[i]->filename)) return i;
  143.   total_files++;
  144.   files=(crced_file **)jrealloc(files,total_files*sizeof(crced_file *),"crc_file_list");
  145.   files[total_files-1]=new crced_file(filename);
  146.   return total_files-1;
  147. }
  148.  
  149. char *crc_manager::get_filename(long filenumber)
  150. {
  151.   CHECK(filenumber>=0 && filenumber<total_files);
  152.   return files[filenumber]->filename;
  153. }
  154.  
  155. ulong crc_manager::get_crc(long filenumber, int &failed)
  156. {    
  157.   CHECK(filenumber>=0 && filenumber<total_files);
  158.   if (files[filenumber]->crc_calculated) 
  159.   {
  160.     failed=0;
  161.     return files[filenumber]->crc;
  162.   }
  163.   failed=1;
  164.   return 0;
  165. }
  166.  
  167. void crc_manager::set_crc(long filenumber, ulong crc)
  168. {
  169.   CHECK(filenumber>=0 && filenumber<total_files);
  170.   files[filenumber]->crc_calculated=1;
  171.   files[filenumber]->crc=crc;
  172. }
  173.  
  174. void cache_list::unmalloc(cache_item *i)
  175. {
  176.   switch (i->type)
  177.   {
  178.     case SPEC_CHARACTER2 :
  179.     case SPEC_CHARACTER : delete ((figure *)i->data);   break;
  180.     case SPEC_FORETILE : delete ((foretile *)i->data);  break;
  181.     case SPEC_BACKTILE : delete ((backtile *)i->data);  break;
  182.     case SPEC_IMAGE    : delete ((image *)i->data);     break;
  183.     case SPEC_EXTERN_SFX : delete ((sound_effect *)i->data); break;
  184.     case SPEC_PARTICLE : delete ((part_frame *)i->data); break;
  185.     case SPEC_EXTERNAL_LCACHE : if (i->data) jfree(i->data); break;
  186.     case SPEC_PALETTE : delete ((char_tint *)i->data); break;
  187.     default :
  188.       printf("Trying to unmalloc unknown type\n");
  189.   }
  190.   i->data=NULL;
  191.   i->last_access=-1;
  192. }
  193.  
  194.  
  195.  
  196. void cache_list::prof_init()
  197. {
  198.   if (prof_data)
  199.     jfree(prof_data);
  200.   
  201.   prof_data=(int *)jmalloc(sizeof(int)*total,"cache profile");
  202.   memset(prof_data,0,sizeof(int)*total);
  203. }
  204.  
  205. static int c_sorter(const void *a, const void *b)
  206. {
  207.   return cash.compare(*(int *)a,*(int *)b);
  208. }
  209.  
  210. int cache_list::compare(int a, int b)
  211. {
  212.   if (prof_data[a]<prof_data[b])
  213.     return 1;
  214.   else if (prof_data[a]>prof_data[b])
  215.     return -1;
  216.   else return 0;
  217. }
  218.  
  219.  
  220. int cache_list::prof_size()
  221. {
  222.   int size=0;     // count up the size for a spec enrty
  223.   size+=2;        // total filenames
  224.   int i;
  225.   for (i=0;i<crc_man.total_filenames();i++)
  226.       size+=strlen(crc_man.get_filename(i))+2;    // filename + 0 + size of string
  227.  
  228.   size+=4;       // number of entries saved
  229.  
  230.   for (i=0;i<total;i++)
  231.     if (list[i].last_access>0)       // don't save unaccessed counts
  232.       size+=2+4+1;                   // filenumber & offset & type
  233.  
  234.   return size;
  235. }
  236.  
  237.  
  238. void cache_list::prof_write(bFILE *fp)
  239. {
  240.   if (prof_data)
  241.   {
  242.     int *ordered_ids=(int *)jmalloc(sizeof(int)*total,"profile order");
  243.     int i;
  244.     for (i=0;i<total;i++) ordered_ids[i]=i;
  245.     qsort(ordered_ids,total,sizeof(int),c_sorter);
  246.  
  247.     if (fp)
  248.     {
  249.       fp->write_short(crc_man.total_filenames());
  250.       for (i=0;i<crc_man.total_filenames();i++)
  251.       {
  252.     int l=strlen(crc_man.get_filename(i))+1;
  253.         fp->write_byte(l);
  254.     fp->write(crc_man.get_filename(i),l);
  255.       }
  256.  
  257.       int tsaved=0;
  258.       for (i=0;i<total;i++)
  259.         if (list[i].last_access>0) tsaved++;
  260.       fp->write_long(tsaved);
  261.  
  262.       for (i=0;i<total;i++)
  263.       {
  264.     int id=ordered_ids[i];
  265.         if (list[id].last_access>0)       // don't save unaccessed counts      
  266.     {
  267.       fp->write_byte(list[id].type);    // save type, if type changed on reload 
  268.                                         // don't cache in-> its a different refrence
  269.       fp->write_short(list[id].file_number);
  270.       fp->write_long(list[id].offset);
  271.     }
  272.       }      
  273.     }
  274.  
  275.     jfree(ordered_ids);
  276.  
  277.   } else dprintf("Cache profiling was not initialized\n");
  278. }
  279.  
  280. void cache_list::prof_uninit()
  281. {
  282.   if (prof_data)
  283.   {
  284.     jfree(prof_data);
  285.     prof_data=NULL;
  286.   }
  287. }
  288.  
  289. int *sorted_id_list;
  290.  
  291.  
  292. static int s_offset_compare(const void *a, const void *b)
  293. {
  294.   return cash.offset_compare(*(int *)a,*(int *)b);
  295. }
  296.  
  297. int cache_list::offset_compare(int a, int b)
  298. {
  299.   if (list[a].offset<list[b].offset)
  300.     return -1;
  301.   else if (list[a].offset>list[b].offset)
  302.     return 1;
  303.   else if (list[a].file_number<list[b].file_number)
  304.     return -1;
  305.   else if (list[a].file_number>list[b].file_number)
  306.     return 1;
  307.   else return 0;
  308. }
  309.  
  310.  
  311. int cache_list::search(int *sarray, ushort filenum, long offset)
  312. {
  313.   int x1=0,x2=total-1;
  314.   int split;
  315.   do
  316.   {
  317.     split=(x1+x2)/2;
  318.     cache_item *e=list+sarray[split];
  319.  
  320.     int comp;
  321.     if (e->offset<offset)      // search to the right    
  322.       x1=split+1;
  323.     else if (e->offset>offset)
  324.       x2=split-1;
  325.     else if (e->file_number<filenum)
  326.       x1=split+1;
  327.     else if (e->file_number>filenum)
  328.       x2=split-1;
  329.     else return sarray[split];
  330.   } while (x1<=x2);
  331.   return -1;
  332. }
  333.  
  334. static int load_chars()  // returns 0 if cache filled
  335. {
  336.   int i;
  337.   for (i=0;i<total_objects;i++)
  338.   {
  339.     if (figures[i]->get_cflag(CFLAG_NEED_CACHE_IN))
  340.     {
  341.       figures[i]->set_cflag(CFLAG_CACHED_IN,0);
  342.       figures[i]->cache_in();
  343.       figures[i]->set_cflag(CFLAG_NEED_CACHE_IN,0);
  344.     }
  345.   }
  346.   return 1;
  347.   
  348. }
  349.  
  350. void cache_list::note_need(int id)
  351. {
  352.   if (list[id].last_access<0)
  353.     list[id].last_access=-2;
  354.   else
  355.     list[id].last_access=2;
  356. }
  357.  
  358. void cache_list::preload_cache_object(int type)
  359. {
  360.   if (type<0xffff)
  361.   {
  362.     if (!figures[type]->get_cflag(CFLAG_NEED_CACHE_IN))  // see if it's already marked
  363.     {        
  364.       figures[type]->set_cflag(CFLAG_NEED_CACHE_IN,1);
  365.       void *cache_fun=figures[type]->get_fun(OFUN_GET_CACHE_LIST);
  366.  
  367.       if (cache_fun)
  368.       {
  369.     int sp=current_space;
  370.     current_space=PERM_SPACE;
  371.  
  372.     void *call_with=NULL;
  373.     push_onto_list(new_lisp_number(type),call_with);
  374.  
  375.     void *cache_list=eval_function((lisp_symbol *)cache_fun,call_with);
  376.     p_ref r1(cache_list);
  377.  
  378.     if (cache_list && lcar(cache_list))
  379.     {
  380.       void *obj_list=lcar(cache_list);
  381.       while (obj_list)
  382.       {
  383.         int t=lnumber_value(CAR(obj_list));
  384.         if (t<0 || t>=total_objects)
  385.           lbreak("Get cache list returned a bad object number %d\n",t);
  386.         else
  387.           preload_cache_object(t);
  388.         obj_list=CDR(obj_list);
  389.       }
  390.     } 
  391.     if (cache_list && lcdr(cache_list))
  392.     {
  393.       void *id_list=lcar(lcdr(cache_list));
  394.       while (id_list)
  395.       {
  396.         int id=lnumber_value(CAR(id_list));
  397.         if (id<0 || id>=total)
  398.           lbreak("Get cache list returned a bad id number %d\n",id);
  399.         else if (list[id].last_access<0)
  400.           list[id].last_access=-2;
  401.         else list[id].last_access=2;
  402.  
  403.         id_list=CDR(id_list);
  404.       }
  405.     }
  406.     current_space=sp;
  407.  
  408.       }
  409.     }
  410.   }
  411. }
  412.  
  413. void cache_list::preload_cache(level *lev)
  414. {
  415.   game_object *f;
  416.   int i;
  417.   for (i=0;i<total_objects;i++)                       // mark all types as not needing loading
  418.     figures[i]->set_cflag(CFLAG_NEED_CACHE_IN,0);
  419.  
  420.   for (f=lev->first_object();f;f=f->next)               // go through each object and get requested items to cache in
  421.     preload_cache_object(f->otype);
  422.  
  423.  
  424.   int j;
  425.   ushort *fg_line;
  426.   for (j=0;j<lev->foreground_height();j++)
  427.   {
  428.     fg_line=lev->get_fgline(j);
  429.     for (i=0;i<lev->foreground_width();i++,fg_line++)
  430.     {
  431.       int id=foretiles[fgvalue(*fg_line)];
  432.       if (id>=0 && id<nforetiles)
  433.       {
  434.     if (list[id].last_access<0)
  435.           list[id].last_access=-2;
  436.     else list[id].last_access=2;      
  437.       }
  438.     }      
  439.   }
  440.  
  441.   ushort *bg_line;
  442.   for (j=0;j<lev->background_height();j++)
  443.   {
  444.     bg_line=lev->get_bgline(j);
  445.     for (i=0;i<lev->background_width();i++,bg_line++)
  446.     {    
  447.       int id=backtiles[bgvalue(*bg_line)];
  448.       if (id>=0 && id<nbacktiles)
  449.       {
  450.     if (list[id].last_access<0)
  451.           list[id].last_access=-2;
  452.     else list[id].last_access=2;      
  453.       }
  454.     }      
  455.   }
  456.  
  457.   load_chars();
  458. }
  459.  
  460. void cache_list::load_cache_prof_info(char *filename, level *lev)
  461. {
  462.   int j;
  463.   for (j=0;j<this->total;j++)
  464.     if (list[j].last_access>=0)      // reset all loaded cache items to 0, all non-load to -1
  465.       list[j].last_access=0;
  466.  
  467.   preload_cache(lev);                // preliminary guesses at stuff to load
  468.  
  469.   int load_fail=1;
  470.   bFILE *fp=open_file(filename,"rb");
  471.   if (!fp->open_failure())
  472.   {
  473.     spec_directory sd(fp);
  474.     spec_entry *se=sd.find("cache profile info");   // see if the cache profile info is in the file
  475.     if (se)
  476.     {
  477.       fp->seek(se->offset,0);
  478.  
  479.       char name[255];
  480.       int tnames=0;
  481.       int *fnum_remap;    // remaps old filenumbers into current ones
  482.       
  483.       tnames=fp->read_short();
  484.       if (tnames)                     /// make sure there isn't bad info in the file
  485.       {
  486.     fnum_remap=(int *)jmalloc(sizeof(int)*tnames,"pfname remap");
  487.  
  488.     int i;
  489.     for (i=0;i<tnames;i++)
  490.     {
  491.       fp->read(name,fp->read_byte());
  492.       fnum_remap[i]=-1;                    // initialize the map to no-map
  493.  
  494.       int j;
  495.       for (j=0;j<crc_man.total_filenames();j++)
  496.         if (!strcmp(crc_man.get_filename(j),name))
  497.           fnum_remap[i]=j;
  498.     }
  499.     
  500.     long tsaved=fp->read_long();
  501.  
  502.  
  503.     int *priority=(int *)jmalloc(tsaved*sizeof(int),"priorities");
  504.     memset(priority,0xff,tsaved*sizeof(int));   // initialize to -1
  505.     int tmatches=0;
  506.  
  507.     sorted_id_list=(int *)jmalloc(sizeof(int)*total,"sorted ids");
  508.     for (j=0;j<total;j++) sorted_id_list[j]=j;
  509.     qsort(sorted_id_list,total,sizeof(int),s_offset_compare);
  510.  
  511.     for (i=0;i<tsaved;i++)
  512.     {
  513.       uchar type=fp->read_byte();
  514.       short file_num=fp->read_short();
  515.       if (file_num>=tnames)  // bad data?
  516.         file_num=-1;
  517.       else file_num=fnum_remap[file_num];
  518.  
  519.       ulong offset=fp->read_long();
  520.  
  521.       // search for a match 
  522.       j=search(sorted_id_list,file_num,offset);     
  523.       if (j!=-1)
  524.       {          
  525.         if (list[j].last_access<0)  // if not loaded
  526.           list[j].last_access=-2;      // mark as needing loading
  527.         else list[j].last_access=2;   // mark as loaded and needing to stay that way
  528.         priority[i]=j;
  529.         tmatches++;
  530.       }
  531.     }
  532.  
  533.     jfree(sorted_id_list);            // was used for searching, no longer needed
  534.  
  535.     for (j=0;j<total;j++)
  536.       if (list[j].last_access==0)
  537.         unmalloc(list+j);             // free any cache entries that are not accessed at all in the level
  538.  
  539.  
  540.     ful=0;
  541.     int tcached=0;
  542.     for (j=0;j<total;j++)    // now load all of the objects until full
  543.     {
  544. //      stat_man->update(j*70/total+25);
  545.       if (list[j].file_number>=0 && list[j].last_access==-2)
  546.       {
  547.         list[j].last_access=-1;
  548.         if (!ful)
  549.         {
  550.           switch (list[j].type)
  551.           {
  552.         case SPEC_BACKTILE : backt(j); break;
  553.         case SPEC_FORETILE : foret(j); break;
  554.         case SPEC_CHARACTER :
  555.         case SPEC_CHARACTER2 : fig(j); break;
  556.         case SPEC_IMAGE : img(j); break;
  557.         case SPEC_PARTICLE : part(j); break;
  558.         case SPEC_EXTERN_SFX : sfx(j); break;
  559.         case SPEC_EXTERNAL_LCACHE : lblock(j); break;
  560.         case SPEC_PALETTE : ctint(j); break;
  561.           }
  562.           tcached++;
  563.         }
  564.       }
  565.     }
  566.     load_fail=0;
  567. //    if (full())
  568. //      dprintf("Cache filled while loading\n");
  569.  
  570.     if (tsaved>tmatches)
  571.       tmatches=tsaved+1;
  572.  
  573.     last_access=tmatches+1;
  574.     for (i=0;i<tsaved;i++)      // reorder the last access of each cache to reflect prioirties
  575.     {
  576.       if (priority[i]!=-1)
  577.       {
  578.         if (list[priority[i]].last_access!=-1)            // make sure this wasn't the last item
  579.           list[priority[i]].last_access=tmatches--;
  580.       }
  581.     } 
  582.  
  583.     jfree(priority);
  584.     jfree(fnum_remap);
  585.  
  586.  
  587.       }
  588.     }    
  589.   }
  590.  
  591.   if (load_fail) // no cache file, go solely on above gueses
  592.   {
  593.     int j;
  594.     for (j=0;j<total;j++)    // now load all of the objects until full, don't free old stuff
  595.     {
  596. //      stat_man->update(j*70/total+25);
  597.  
  598.       if (list[j].file_number>=0 && list[j].last_access==-2)
  599.       {
  600.     list[j].last_access=-1;
  601.     if (!ful)
  602.     {
  603.       switch (list[j].type)
  604.       {
  605.         case SPEC_BACKTILE : backt(j); break;
  606.         case SPEC_FORETILE : foret(j); break;
  607.         case SPEC_CHARACTER :
  608.         case SPEC_CHARACTER2 : fig(j); break;
  609.         case SPEC_IMAGE : img(j); break;
  610.         case SPEC_PARTICLE : part(j); break;
  611.         case SPEC_EXTERN_SFX : sfx(j); break;
  612.         case SPEC_EXTERNAL_LCACHE : lblock(j); break;
  613.         case SPEC_PALETTE : ctint(j); break;
  614.       }
  615.     }
  616.       }
  617.     }
  618.     if (full())
  619.       dprintf("Cache filled while loading\n");
  620.   }
  621.   delete fp;
  622. }
  623.  
  624.  
  625. void cache_list::prof_poll_start()
  626. {
  627.   poll_start_access=last_access;  
  628. }
  629.  
  630. void cache_list::prof_poll_end()
  631. {
  632.   if (prof_data)
  633.   {
  634.     int i=0;
  635.     for (;i<total;i++)
  636.     {
  637.       if (list[i].last_access>=poll_start_access)
  638.         prof_data[i]++;
  639.     }
  640.   }
  641. }
  642.  
  643. void cache_list::unreg(int id)
  644. {
  645.   if (list[id].file_number)
  646.   {
  647.     unmalloc(&list[id]);
  648.     list[id].file_number=-1;
  649.   }
  650.   else 
  651.     printf("Error : trying to unregister free object\n");
  652. }
  653.  
  654. void cache_cleanup2()
  655. { unlink(lfname); 
  656. }
  657.  
  658. void cache_cleanup(int ret, void *arg)
  659. { unlink(lfname); 
  660. }
  661.  
  662. FILE *open_FILE(char *filename, char *mode);
  663. extern char *macify_name(char *s);
  664.  
  665. void cache_list::create_lcache()
  666. {
  667. #ifdef __WATCOMC__
  668.   char *prefix="c:\\";
  669. #else
  670.   char *prefix="/tmp/";     // for UNIX store lisp cache in tmp dir
  671.   int flags=O_CREAT | O_RDWR;
  672. #endif
  673.  
  674.   int cfail=1,num=0;
  675.   do
  676.   {
  677.     sprintf(lfname,"%slcache%02d.tmp",prefix,num);
  678.  
  679. #if defined( __WATCOMC__ ) || defined( __POWERPC__ )
  680.     unlink(lfname);
  681. #ifdef __POWERPC__
  682.         macify_name(lfname);
  683. #endif
  684.     FILE *fp=fopen(lfname,"wb");
  685.     if (fp) 
  686.     {
  687.         fclose(fp);
  688.         cfail=0;
  689.         }
  690. #else
  691.     int fd=open(lfname,flags,S_IRWXU | S_IRWXG | S_IRWXO);     // can we get exclusive rights to this file?
  692.     if (fd<0) close(fd); else cfail=0;
  693. #endif
  694.  
  695.     if (cfail)
  696.       num++;
  697.  
  698.   } while (cfail && num<15);
  699.   if (cfail)
  700.   {
  701.     fprintf(stderr,"Error : Unable to open cache file for compiled code.\n"
  702.         "        Please delete all files named lcacheXX.tmp\n"
  703.         "        and make sure you have write permission to\n"
  704.         "        directory (%s)\n",prefix);
  705.     exit(0);
  706.   } else
  707.   {
  708.     exit_proc(cache_cleanup,cache_cleanup2);    // make sure this file gets deleted on exit..
  709.   }
  710.   lcache_number=-1;
  711. }
  712.  
  713. cache_list::cache_list()
  714. {
  715.   // start out with a decent sized cache buffer because it's going to get allocated anyway. 
  716.   total=0; 
  717.   list=NULL;
  718.   last_registered=-1;   
  719.   cache_file=fp=NULL; 
  720.   last_access=1;
  721.   used=ful=0;
  722.   last_dir=NULL;
  723.   last_file=-1;
  724.   prof_data=NULL;
  725.   cache_read_file=NULL;
  726.   create_lcache();
  727. }
  728.  
  729. cache_list::~cache_list()
  730. }
  731.  
  732. void cache_list::empty()
  733. {
  734.   for (int i=0;i<total;i++)
  735.   {
  736.     if (list[i].file_number>=0 && list[i].last_access!=-1)
  737.       unmalloc(&list[i]);
  738.   }
  739.   jfree(list);
  740.   if (fp) delete fp;
  741.   if (last_dir) delete last_dir;
  742.   if (cache_file)
  743.   {
  744.     delete cache_file;
  745.     cache_file=NULL;    
  746.   }
  747.   unlink(lfname); 
  748.  
  749.   if (prof_data)
  750.   {
  751.     delete prof_data;
  752.     prof_data=NULL;
  753.   }
  754.  
  755.   total=0;                    // reinitalize
  756.   list=NULL;
  757.   last_registered=-1;   
  758.   cache_file=fp=NULL; 
  759.   if (cache_read_file) 
  760.   {
  761.     delete cache_read_file;
  762.     cache_read_file=NULL;
  763.   }
  764.  
  765.   last_access=1;
  766.   used=ful=0;
  767.   last_dir=NULL;
  768.   last_file=-1;
  769.   prof_data=NULL;
  770. }
  771.  
  772. void cache_list::locate(cache_item *i, int local_only)
  773. {
  774. //  dprintf("cache in %s, type %d, offset %d\n",crc_man.get_filename(i->file_number),i->type,i->offset);
  775.   if (i->file_number!=last_file)
  776.   {
  777.     if (fp) delete fp;
  778.     if (last_dir) delete last_dir; 
  779.     if (local_only)
  780.       fp=new jFILE(crc_man.get_filename(i->file_number),"rb");
  781.     else
  782.       fp=open_file(crc_man.get_filename(i->file_number),"rb");
  783.  
  784.  
  785.     if (fp->open_failure())
  786.     {
  787.       printf("Ooch. Could not open file %s\n",crc_man.get_filename(i->file_number));
  788.       delete fp;
  789.       exit(0);
  790.     }
  791.  
  792.     last_offset=-1;
  793.     last_dir=new spec_directory(fp);
  794.     last_file=i->file_number;
  795.   }
  796.   if (i->offset!=last_offset)
  797.   {
  798.     fp->seek(i->offset,SEEK_SET);
  799.     last_offset=i->offset;
  800.   }
  801.   used=1;
  802. }
  803.  
  804. long cache_list::alloc_id()
  805. {
  806.   int id;
  807.   if (prof_data)
  808.   {
  809.     the_game->show_help("new id allocated, cache profiling turned off\n");
  810.     prof_uninit();
  811.   }
  812.  
  813.   // see if we previously allocated an id, if so check the next spot in the array
  814.   // otherwise we will have to scan the whole list for a free id and possible 
  815.   // grow the list.
  816.   if (last_registered+1<total && list[last_registered+1].file_number<0)
  817.     id=last_registered+1;
  818.   else
  819.   {
  820.     int i;
  821.     cache_item *ci=list;
  822.     for (i=0,id=-1;i<total && id<0;i++,ci++)        // scan list for a free id
  823.     {
  824.       if (ci->file_number<0)
  825.         id=i;
  826.     }
  827.  
  828.     if (id<0)                                 // if no free id's then make list bigger
  829.     {
  830.       int add_size=20;
  831.       list=(cache_item *)jrealloc(list,(sizeof(cache_item)*(total+add_size)),"Cache list");
  832.       for (i=0;i<add_size;i++)
  833.       {
  834.         list[total+i].file_number=-1;         // mark new entries as new
  835.     list[total+i].last_access=-1;
  836.     list[total+i].data=NULL;
  837.       }
  838.       id=total;
  839.       if (prof_data)                          // new id's have been added old prof_data size won't work
  840.       { jfree(prof_data); prof_data=NULL; }
  841.       total+=add_size;
  842.     }
  843.   }
  844.   last_registered=id;
  845.   return id;
  846. }
  847.  
  848.  
  849.  
  850. long cache_list::reg_lisp_block(Cell *block)
  851.   long s;
  852.   if (lcache_number==-1)
  853.     lcache_number=crc_man.get_filenumber(lfname);
  854.  
  855.   if (can_cache_lisp())
  856.   {
  857.     if (!cache_file)
  858.     {
  859.       if (cache_read_file)
  860.       {
  861.                 delete cache_read_file;
  862.                 cache_read_file=NULL;
  863.             
  864.                 cache_file=new jFILE(lfname,"ab");    
  865.       } else cache_file=new jFILE(lfname,"wb");     // first time we opened
  866.  
  867.     }
  868.     if (cache_file->open_failure()) 
  869.     { 
  870.       delete cache_file;
  871.       lprint(block);
  872.       fprintf(stderr,"Unable to open lisp cache file name %s\n",lfname);
  873.       exit(0);
  874.     }
  875.   }
  876.   int id=alloc_id(),i,fn=crc_man.get_filenumber(lfname);
  877.   cache_item *ci=list+id;
  878.   CHECK(id<total && list[id].file_number<0);
  879.  
  880.   ci->file_number=fn;
  881.   ci->last_access=-1;
  882.   ci->type=SPEC_EXTERNAL_LCACHE;
  883.   if (!can_cache_lisp()) 
  884.   {
  885.     ci->data=(void *)block;                // we can't cache it out so it must be in memory
  886.     return id;
  887.   } 
  888.   ci->data=NULL;                  // assume that it is in tmp memory, need to cache in on access
  889.   ci->offset=cache_file->tell();
  890.  
  891.   s=block_size(block);
  892.   cache_file->write_long(s);
  893.   write_level(cache_file,block);
  894.   return id;    
  895. }
  896.  
  897. long cache_list::reg_object(char *filename, void *object, int type, int rm_dups)
  898.   char *name;
  899.   if (item_type(object)==L_CONS_CELL)      // see if we got a object with a filename included
  900.   {
  901.     filename=lstring_value(lcar(object));
  902.     name=lstring_value(lcdr(object));
  903.   }
  904.   else name=lstring_value(object);        // otherwise should be a string
  905.   return reg(filename,name,type,rm_dups);
  906. }
  907.  
  908. extern int total_files_open;
  909.  
  910. long cache_list::reg(char *filename, char *name, int type, int rm_dups)
  911.   int id=alloc_id(),i,fn=crc_man.get_filenumber(filename);
  912.   cache_item *ci=list+id;
  913.   CHECK(id<total && list[id].file_number<0);
  914.  
  915.   if (type==SPEC_EXTERN_SFX)    // if a extern sound effect then just make sure it's there
  916.   {
  917.     bFILE *check=open_file(filename,"rb");
  918.     if (check->open_failure())
  919.     {
  920.       delete check;
  921.       printf("Unable to open file '%s' for reading\n",filename);
  922.       exit(0);
  923.     }
  924.     char buf[4];
  925.     check->read(buf,4);
  926.     delete check;
  927.     if (memcmp(buf,"RIFF",4))
  928.     {
  929.       printf("File %s is not a WAV file\n",filename);
  930.       exit(0);
  931.     }
  932.     ci->file_number=fn;
  933.     ci->last_access=-1;
  934.     ci->data=NULL;
  935.     ci->offset=0;
  936.     ci->type=type;  
  937.     return id;  
  938.   }
  939.  
  940.   spec_directory *sd=sd_cache.get_spec_directory(filename);
  941.   
  942.   if (!sd)
  943.   {
  944.     printf("Unable to open filename %s for requested item %s\n",filename,name);
  945.     exit(0);
  946.   }
  947.  
  948.   spec_entry *se;
  949.   if (type!=-1)
  950.   {
  951.     se=sd->find(name,type);
  952.     if (!se) se=sd->find(name);
  953.   }
  954.   else se=sd->find(name);
  955.   
  956.   
  957.   if (!se)
  958.   {    
  959.     printf("No such item %s in file %s\n",name,filename);
  960.     exit(0);
  961.   }
  962.   else if (type>=0 && (type!=se->type && ((type!=SPEC_CHARACTER2 && type!=SPEC_CHARACTER)  ||
  963.                       (se->type!=SPEC_CHARACTER && se->type!=SPEC_CHARACTER2))))
  964.   {
  965.     printf("Item %s of file %s should be type %s\n",name,filename,spec_types[type]);
  966.     exit(0);
  967.   }
  968.  
  969.       
  970.  
  971.   if (rm_dups)
  972.   {
  973.     for (i=0;i<total;i++)
  974.       if (list[i].file_number==fn && list[i].offset==se->offset)
  975.         return i;
  976.   }
  977.  
  978.   ci->file_number=fn;
  979.   ci->last_access=-1;
  980.   ci->data=NULL;
  981.   ci->offset=se->offset;
  982.   ci->type=se->type;  
  983.   return id;  
  984. }
  985.  
  986.  
  987. void cache_list::normalize()
  988. {
  989.   int j;
  990.   cache_item *ci=list;
  991.   last_access=-1;
  992.   for (j=0;j<total;j++,ci++)
  993.   {
  994.     if (ci->last_access>=0)
  995.       ci->last_access=ci->last_access>>16;        // shift everything over by 16
  996.     if (ci->last_access>last_access)            //  and find new largest timestamp
  997.       last_access=ci->last_access;
  998.   }
  999.   last_access++;
  1000. }
  1001.  
  1002. backtile *cache_list::backt(int id)
  1003. {
  1004.   cache_item *me=list+id;
  1005.   CONDITION(id<total && id>=0 && me->file_number>=0,"Bad id");
  1006.  
  1007.   if (me->last_access>=0)  
  1008.   {
  1009.     touch(me);
  1010.     return (backtile *)me->data;
  1011.   }
  1012.   else
  1013.   {
  1014.     touch(me);
  1015.     locate(me);
  1016.     int sp=alloc_space; alloc_space=ALLOC_SPACE_CACHE;
  1017.     me->data=(void *)new backtile(fp);
  1018.     alloc_space=sp;
  1019.     last_offset=fp->tell();
  1020.     return (backtile *)me->data;
  1021.   }  
  1022. }
  1023.  
  1024.  
  1025. foretile *cache_list::foret(int id)
  1026. {
  1027.   cache_item *me=list+id;
  1028.   CONDITION(id<total && id>=0 && me->file_number>=0,"Bad id");
  1029.  
  1030.   if (me->last_access>=0)  
  1031.   {
  1032.     touch(me);
  1033.     return (foretile *)me->data;
  1034.   }
  1035.   else
  1036.   {
  1037.     touch(me);
  1038.     locate(me);
  1039.     int sp=alloc_space; alloc_space=ALLOC_SPACE_CACHE;
  1040.     me->data=(void *)new foretile(fp);
  1041.     alloc_space=sp;
  1042.     last_offset=fp->tell();
  1043.     return (foretile *)me->data;
  1044.   }  
  1045. }
  1046.  
  1047. figure *cache_list::fig(int id)
  1048. {
  1049.   cache_item *me=list+id;
  1050. //  CONDITION(id<total && id>=0 && me->file_number>=0,"Bad id");
  1051.   if (me->last_access>=0)  
  1052.   {
  1053.     touch(me);
  1054.     return (figure *)me->data;
  1055.   }
  1056.   else
  1057.   {
  1058.     touch(me);
  1059.     locate(me);
  1060.     int sp=alloc_space; alloc_space=ALLOC_SPACE_CACHE;
  1061.     me->data=(void *)new figure(fp,me->type);
  1062.     alloc_space=sp;
  1063.     last_offset=fp->tell();
  1064.     return (figure *)me->data;
  1065.   }  
  1066. }
  1067.  
  1068. image *cache_list::img(int id)
  1069. {
  1070.   cache_item *me=list+id;
  1071.   CONDITION(id<total && id>=0 && me->file_number>=0,"Bad id");
  1072.   if (me->last_access>=0)  
  1073.   {
  1074.     touch(me);
  1075.     return (image *)me->data;
  1076.   }
  1077.   else
  1078.   {
  1079.     touch(me);                                           // hold me, feel me, be me!
  1080.     locate(me);
  1081.     int sp=alloc_space; alloc_space=ALLOC_SPACE_CACHE;
  1082.     image *im=new image(fp);
  1083.     alloc_space=sp;
  1084.     me->data=(void *)im;
  1085.     last_offset=fp->tell();
  1086.  
  1087.     return (image *)me->data;
  1088.   }  
  1089. }
  1090.  
  1091. sound_effect *cache_list::sfx(int id)
  1092. {
  1093.   cache_item *me=list+id;
  1094.   CONDITION(id<total && id>=0 && me->file_number>=0,"Bad id");
  1095.   if (me->last_access>=0)  
  1096.   {
  1097.     touch(me);                                           // hold me, feel me, be me!
  1098.     return (sound_effect *)me->data;
  1099.   }
  1100.   else
  1101.   {
  1102.     touch(me);                                           // hold me, feel me, be me!
  1103.     char *fn=crc_man.get_filename(me->file_number);
  1104.     int sp=alloc_space; alloc_space=ALLOC_SPACE_CACHE;
  1105.     me->data=(void *)new sound_effect(fn);
  1106.     alloc_space=sp;
  1107.     return (sound_effect *)me->data;
  1108.   }  
  1109. }
  1110.  
  1111.  
  1112. part_frame *cache_list::part(int id)
  1113. {
  1114.   cache_item *me=list+id;
  1115.   CONDITION(id<total && id>=0 && me->file_number>=0,"Bad id");
  1116.   if (me->last_access>=0)  
  1117.   {
  1118.     touch(me);                                           // hold me, feel me, be me!
  1119.     return (part_frame *)me->data;
  1120.   }
  1121.   else
  1122.   {
  1123.     touch(me);
  1124.     locate(me);
  1125.     int sp=alloc_space; alloc_space=ALLOC_SPACE_CACHE;
  1126.     me->data=(void *)new part_frame(fp);
  1127.     alloc_space=sp;
  1128.     last_offset=fp->tell();
  1129.     return (part_frame *)me->data;
  1130.   }  
  1131. }
  1132.  
  1133.  
  1134. Cell *cache_list::lblock(int id)
  1135. {
  1136.   cache_item *me=list+id;
  1137.   CONDITION(id<total && id>=0 && me->file_number>=0,"Bad id");
  1138.   if (!can_cache_lisp()) return (Cell *)me->data;
  1139.   if (me->last_access>=0)  
  1140.   {
  1141.     touch(me);
  1142.     return (Cell *)me->data;
  1143.   }
  1144.   else
  1145.   {
  1146.     if (cache_file)
  1147.     {
  1148.       delete cache_file;
  1149.       cache_file=NULL;
  1150.     } 
  1151.     touch(me);
  1152.  
  1153.     if (!cache_read_file)
  1154.     {
  1155.       cache_read_file=new jFILE(crc_man.get_filename(me->file_number),"rb");
  1156.       
  1157.       int cache_size=80*1024;                   // 80K
  1158.       cache_read_file->set_read_buffer_size(cache_size); 
  1159.       uchar mini_buf;
  1160.       cache_read_file->read(&mini_buf,1);       // prime the buffer
  1161.     }
  1162.  
  1163.     cache_read_file->seek(me->offset,0);
  1164.  
  1165.     int sp=alloc_space; alloc_space=ALLOC_SPACE_CACHE;
  1166.  
  1167.     long size=cache_read_file->read_long();
  1168.     void *space;
  1169.  
  1170.     if (size)
  1171.       space=jmalloc(size,"cached lisp block");
  1172.     else space=NULL;
  1173.  
  1174.     int cs=current_space;
  1175.     use_user_space(space,size);    
  1176.     load_block(cache_read_file);
  1177.     current_space=cs;
  1178.     
  1179.     alloc_space=sp;
  1180.     if (size)
  1181.       me->data=(Cell *)space;
  1182.     else me->data=NULL;
  1183.     return (Cell *)me->data;
  1184.   }  
  1185. }
  1186.  
  1187. cache_list cash;
  1188.  
  1189. void free_up_memory()
  1190. {
  1191.   cash.free_oldest();
  1192. }
  1193.  
  1194. void cache_list::free_oldest()
  1195. {
  1196.   long i,old_time=last_access;
  1197.   cache_item *ci=list,*oldest=NULL;
  1198.   ful=1;
  1199.  
  1200.   for (i=0;i<total;i++,ci++)
  1201.   {
  1202.     if (ci->data && ci->last_access<old_time)
  1203.     {
  1204.       oldest=ci;
  1205.       old_time=ci->last_access;
  1206.     }
  1207.   }
  1208.   if (oldest)
  1209.   {
  1210.     dprintf("mem_maker : freeing %s\n",spec_types[oldest->type]);
  1211.     unmalloc(oldest);    
  1212.   }
  1213.   else
  1214.   {
  1215.     close_graphics();
  1216.     printf("Out of memory, please remove any TSR's device drivers you can\n");
  1217.     mem_report("out_of_mem");
  1218.     exit(0);
  1219.   }         
  1220. }
  1221.  
  1222.  
  1223. void cache_list::show_accessed()
  1224. {
  1225.   int old=last_access,new_old_accessed;
  1226.   cache_item *ci,*new_old;
  1227.   
  1228.   do
  1229.   {
  1230.     new_old_accessed=-1;
  1231.     new_old=NULL;
  1232.     ci=list;
  1233.     for (int i=0;i<total;i++,ci++)  
  1234.     {
  1235.       if (ci->last_access<old && ci->last_access>0 && ci->last_access>new_old_accessed)    
  1236.       {
  1237.     new_old_accessed=ci->last_access;
  1238.         new_old=ci;    
  1239.       }
  1240.     }
  1241.     if (new_old)
  1242.     {
  1243.       ci=new_old;
  1244.       old=ci->last_access;
  1245.       printf("type=(%20s) file=(%20s) access=(%6d)\n",spec_types[ci->type],
  1246.          crc_man.get_filename(ci->file_number),
  1247.          ci->last_access);
  1248.     }
  1249.   } while (new_old);
  1250. }
  1251.  
  1252.  
  1253. int cache_list::loaded(int id)
  1254. {
  1255.   cache_item *me=list+id;
  1256.   CONDITION(id<total && id>=0 && me->file_number>=0,"Bad id");
  1257.   if (me->last_access>=0)  
  1258.     return 1;
  1259.   else return 0;
  1260. }
  1261.  
  1262.  
  1263.  
  1264. char_tint *cache_list::ctint(int id)
  1265. {
  1266.   cache_item *me=list+id;
  1267.   CONDITION(id<total && id>=0 && me->file_number>=0,"Bad id" && me->type==SPEC_PALETTE);
  1268.   if (me->last_access>=0)  
  1269.   {
  1270.     touch(me);
  1271.     return (char_tint *)me->data;
  1272.   }
  1273.   else
  1274.   {
  1275.     touch(me);
  1276.     locate(me);
  1277.     int sp=alloc_space; alloc_space=ALLOC_SPACE_CACHE;
  1278.     me->data=(void *)new char_tint(fp);
  1279.     alloc_space=sp;
  1280.     last_offset=fp->tell();
  1281.     return (char_tint *)me->data;
  1282.   }    
  1283. }
  1284.  
  1285.  
  1286.  
  1287.  
  1288.